#include "PWMOutput.h"
#include "IoServiceSource.h"
#include "FactoriesKeeper.h"

#include <boost/asio.hpp>
#include <boost/lexical_cast.hpp>

using boost::posix_time::milliseconds;

using SRCLF::Config::Section;

namespace SRCLF
{
namespace IO
{

	PWMOutput::PWMOutput(const string& name, const Configuration& config)
		: timer( getCommonIOService() )
	{
		const Section& config_section = config.getSection(Section::input, name);

		//Wrrapped output name
		string wrapped_output_name = config_section.getScalarByKey("wrapped_output");
		wrapped_output = shared_ptr<IOperatedOutput>( FactoriesKeeper::getInstance().newOutputInstance(wrapped_output_name, config) );

		minimal_value = boost::lexical_cast<double>(config_section.getScalarByKey("minimal_value"));
		maximal_value = boost::lexical_cast<double>(config_section.getScalarByKey("maximal_value"));

		pulses_period = boost::lexical_cast<double>(config_section.getScalarByKey("pulses_period"));
	}

	void PWMOutput::adminCommand(const string& command, string& result)
	{
		wrapped_output->adminCommand(command, result);
	}

	void PWMOutput::controlCommand(const string& command, string& result)
	{
		wrapped_output->controlCommand(command, result);
	}

	void PWMOutput::infoCommand(string& command, string& result)
	{
		wrapped_output->infoCommand(command, result);
	}

	void PWMOutput::onTimerAction() 
	{
		//PWM Logic
		ptime next_change_time; 
		
		if ( current_state == 0 ) 
		{
			current_state = 1;
			next_change_time += milliseconds( 1000.0 * duty_cycle * pulses_period );
			wrapped_output->setOutput( maximal_value );
		}
		else
		{
			current_state = 0;
			next_change_time += milliseconds( 1000.0 * (1.0 - duty_cycle) * pulses_period );
			wrapped_output->setOutput( minimal_value );
		}

		//Reschedule action
		timer.expires_at(next_change_time);
		timer.async_wait(boost::bind(&PWMOutput::onTimerAction, this));
	}

}
}
